package com.qianxunclub.util;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.util.StringUtils;

public class DateUtils
{

	private static final Log log = LogFactory.getLog(DateUtils.class);
	public static final String FORMAT_YYYY_MM_DD_HH_MM = "yyyy-MM-dd HH:mm";
	public static final String PATTEM_YYYYMMDD = "yyyyMMdd";
	public static final String PATTEM_DATE = "yyyy-MM-dd";
	public static final String PATTEM_MONTH = "yyyy-MM";
	public static final String PATTEM_TIME = "HH:mm:ss";
	public static final String PATTEM_DATE_TIME = "yyyy-MM-dd HH:mm:ss";

	public static final String PATTEM_TIMESTAMP = "yyyy-MM-dd HH:mm:ss.SSS";

	public static final String PATTEM_DAY_BEGIN = "yyyy-MM-dd 00:00:00";
	public static final String PATTEM_DAY_END = "yyyy-MM-dd 23:59:59";
	public static final long ONEDAY_MILLISECONDS = 24 * 60 * 60 * 1000;
	public static final long ONEMIN_MILLISECONDS = 60 * 1000; //一分钟的毫秒数
	public static final int DATE_COMPARE_BEFORE = -1;
	public static final int DATE_COMPARE_BETWEEN = 0;
	public static final int DATE_COMPARE_AFTER = 1;
	// yyyyMMdd 格式正则
    public static final String YYYY_MM_DD_DATE_FORMAT_REGEXP = "^(?:(?!0000)[0-9]{4}-(?:(?:0[1-9]|1[0-2])-(?:0[1-9]|1[0-9]|2[0-8])|(?:0[13-9]|1[0-2])-(?:29|30)|(?:0[13578]|1[02])-31)|(?:[0-9]{2}(?:0[48]|[2468][048]|[13579][26])|(?:0[48]|[2468][048]|[13579][26])00)-02-29)$";

	/**
	 * 转换时间对象  匹配格式 yyyy-MM-dd; yyyy-MM-dd HH:mm; yyyy-MM-dd HH:mm:ss; EEE MMM dd HH:mm:ss 'CST' yyyy;
	 * @param stringValue
	 * @return
	 */
	public static Date parse(String stringValue)
	{
		Date date = null;
		SimpleDateFormat format = new SimpleDateFormat(PATTEM_DATE);

		try
		{
			date = format.parse(stringValue);
		}
		catch (ParseException e)
		{
		}

		if (date == null)
		{
			try
			{
				format.applyPattern(PATTEM_DATE_TIME);
				date = format.parse(stringValue);
			}
			catch (ParseException e)
			{
			}
		}
		if (date == null)
		{
			try
			{
				format.applyPattern(FORMAT_YYYY_MM_DD_HH_MM);
				date = format.parse(stringValue);
			}
			catch (ParseException e)
			{
			}
		}

		if (date == null)
		{
			try
			{
				format = new SimpleDateFormat("EEE MMM dd HH:mm:ss 'CST' yyyy", Locale.US);
				date = format.parse(stringValue);
			}
			catch (ParseException e)
			{
			}
		}

		return date;
	}

	public static String getTime()
	{
		SimpleDateFormat fmt = new SimpleDateFormat("HH:mm:ss");
		return fmt.format(new Date());
	}

	public static String getDate()
	{
		return getDate(new Date());
	}
	public static String getDate(Date date)
	{
		SimpleDateFormat fmt = new SimpleDateFormat(PATTEM_DATE);
		return fmt.format(date);
	}
	public static String getDateTime()
	{
		return getDateTime(new Date());
	}
	public static String getDateTime(Date date)
	{
		SimpleDateFormat fmt = new SimpleDateFormat(PATTEM_DATE_TIME);
		return fmt.format(date);
	}
	public static String getDateByFileName()
	{
		SimpleDateFormat fmt = new SimpleDateFormat("yyyyMMdd");
		return fmt.format(new Date());
	}
	/**
     * 将字符串转换成时间
     *
     * @param value
     * @param pattem 格式
     * @return 时间类型对象
     * @author boll
     */
    public static Date getDate(String value, String pattem) {
        if (null == pattem || "".equals(pattem)) {
            pattem = PATTEM_DATE_TIME;
        }
        SimpleDateFormat format = new SimpleDateFormat(pattem);
        try {
            return format.parse(value);
        } catch (Exception e) {
            e.printStackTrace();
            log.error("date parse exception pattem=" + pattem + ",date=" + value);
            return null;
        }
    }

    /**
     * 把字符转换成时间，格式为默认格式
     *
     * @param value
     * @return 时间类型对象
     * @author @boll
     */
    public static Date getDate(String value) {
        return getDate(value, PATTEM_DATE_TIME);
    }

    public static Date getDateRand(String date) {
        Date returnDate = getDate(date);
        if (returnDate == null) {
            returnDate = getDate(date, PATTEM_TIMESTAMP);
        }
        return returnDate;
    }

    /**
     * 格式化时间
     *
     * @param date   时间
     * @param pattem 格式
     * @return 字符串类型的时间
     * @author boll
     */
    public static String formatDate(Date date, String pattem) {
        if (date != null) {
            try {
                SimpleDateFormat format = new SimpleDateFormat(pattem);
                return format.format(date);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return "";
    }

    /**
     * 以默认格式格式化时间
     * yyyy-MM-dd HH:mm:ss
     *
     * @param date 时间
     * @return 字符串类型的时间
     * @author boll
     */
    public static String formatDate(Date date) {
        return formatDate(date, PATTEM_DATE_TIME);
    }

    /**
     * 以yyyy-MM-dd 格式化日期
     *
     * @param date
     * @return
     */
    public static String formatDateYMD(Date date) {
        return formatDate(date, PATTEM_DATE);
    }

    /**
     * 以yyyy-MM 格式化日期
     *
     * @param date
     * @return
     */
    public static String formatDateYM(Date date) {
        return formatDate(date, PATTEM_MONTH);
    }

    /**
     * @param date
     * @return
     */
    public static int getAnimalSign(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        int year = cal.get(Calendar.YEAR);
        return getAnimalSign(year);
    }

    /**
     * @param year
     * @return
     */
    public static int getAnimalSign(int year) {
        year = year - 1899;
        year = year % 12;
        return Integer.valueOf(year != 0 ? year : 12).shortValue();
    }

    public static int getConstellation(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        int year = cal.get(Calendar.YEAR);
        int day = cal.get(Calendar.DAY_OF_YEAR);

        Calendar calBegin = Calendar.getInstance();
        Calendar calEnd = Calendar.getInstance();

        calBegin.set(year, 2, 21);
        calEnd.set(year, 3, 20);
        if (day >= calBegin.get(Calendar.DAY_OF_YEAR) && day <= calEnd.get(Calendar.DAY_OF_YEAR)) {
            return 1;
        }
        calBegin.set(year, 3, 21);
        calEnd.set(year, 4, 20);
        if (day >= calBegin.get(Calendar.DAY_OF_YEAR) && day <= calEnd.get(Calendar.DAY_OF_YEAR)) {
            return 2;
        }
        calBegin.set(year, 4, 21);
        calEnd.set(year, 5, 21);
        if (day >= calBegin.get(Calendar.DAY_OF_YEAR) && day <= calEnd.get(Calendar.DAY_OF_YEAR)) {
            return 3;
        }
        calBegin.set(year, 5, 22);
        calEnd.set(year, 6, 22);
        if (day >= calBegin.get(Calendar.DAY_OF_YEAR) && day <= calEnd.get(Calendar.DAY_OF_YEAR)) {
            return 4;
        }
        calBegin.set(year, 6, 23);
        calEnd.set(year, 7, 22);
        if (day >= calBegin.get(Calendar.DAY_OF_YEAR) && day <= calEnd.get(Calendar.DAY_OF_YEAR)) {
            return 5;
        }
        calBegin.set(year, 7, 23);
        calEnd.set(year, 8, 22);
        if (day >= calBegin.get(Calendar.DAY_OF_YEAR) && day <= calEnd.get(Calendar.DAY_OF_YEAR)) {
            return 6;
        }
        calBegin.set(year, 8, 23);
        calEnd.set(year, 9, 22);
        if (day >= calBegin.get(Calendar.DAY_OF_YEAR) && day <= calEnd.get(Calendar.DAY_OF_YEAR)) {
            return 7;
        }
        calBegin.set(year, 9, 23);
        calEnd.set(year, 10, 21);
        if (day >= calBegin.get(Calendar.DAY_OF_YEAR) && day <= calEnd.get(Calendar.DAY_OF_YEAR)) {
            return 8;
        }
        calBegin.set(year, 10, 22);
        calEnd.set(year, 11, 21);
        if (day >= calBegin.get(Calendar.DAY_OF_YEAR) && day <= calEnd.get(Calendar.DAY_OF_YEAR)) {
            return 9;
        }
        calBegin.set(year, 11, 22);
        calEnd.set(year, 0, 19);
        if (day >= calBegin.get(Calendar.DAY_OF_YEAR) || day <= calEnd.get(Calendar.DAY_OF_YEAR)) {
            return 10;
        }
        calBegin.set(year, 0, 20);
        calEnd.set(year, 1, 19);
        if (day >= calBegin.get(Calendar.DAY_OF_YEAR) && day <= calEnd.get(Calendar.DAY_OF_YEAR)) {
            return 11;
        }
        calBegin.set(year, 1, 20);
        calEnd.set(year, 2, 20);
        if (day >= calBegin.get(Calendar.DAY_OF_YEAR) && day <= calEnd.get(Calendar.DAY_OF_YEAR)) {
            return 12;
        }
        return 0;
    }

    /**
     * 通过出生日期计算年龄，yyyyMMdd 算足岁生日
     *
     * @param birthday String
     * @return
     */
    public static int computeAge(String birthday) {
        return computeAge(getDate(birthday, "yyyyMMdd"));
    }

    /**
     * @param birthday
     * @return
     * @throws Exception
     */
    public static int computeAge(Date birthday) {
        if (birthday == null) {
            return 0;
        }
        Calendar cal = Calendar.getInstance();
        cal.setTime(birthday);
        Calendar now = Calendar.getInstance();
        int age = now.get(Calendar.YEAR) - cal.get(Calendar.YEAR);
        cal.add(Calendar.YEAR, age);
        if ((cal.get(Calendar.MONTH) > now.get(Calendar.MONTH)) || (cal.get(Calendar.MONTH) == now.get(Calendar.MONTH) && cal.get(Calendar.DAY_OF_MONTH) > now.get(Calendar.DAY_OF_MONTH))) {
            age--;
        }

        return age;
    }

    /**
     * 获得当前时间的默认格式字符串
     *
     * @return 字符串类型的时间
     * @author @boll
     */
    public static String now() {
        return formatDate(new Date());
    }

    /**
     * 获得今天时间日期格式的字符串
     *
     * @return 字符串类型的日期
     * @author boll
     */
    public static String getToday() {
        return formatDate(new Date(), PATTEM_DATE);
    }

    /**
     * 获得明天时间日期格式的字符串
     *
     * @return 字符串类型的日期
     * @author boll
     */
    public static String getTomorrow() {
        long time = new Date().getTime() + ONEDAY_MILLISECONDS;
        return formatDate(new Date(time), PATTEM_DATE);
    }

    /**
     * 获得昨时间日期格式的字符
     *
     * @return 字符串类型的日期
     * @author boll
     */
    public static String getYesterday() {
        long time = new Date().getTime() - ONEDAY_MILLISECONDS;
        return formatDate(new Date(time), PATTEM_DATE);
    }

    /**
     * 获得今天开始时间点 如：2011-09-09 00:00:00
     *
     * @return
     * @author boll
     */
    public static String getTodayBegin() {
        return formatDate(new Date(), PATTEM_DAY_BEGIN);
    }

    /**
     * 获得今天的结束时间  如：2011-09-09 23:59:59
     *
     * @return 今天的结束时间
     * @author boll
     */
    public static String getTodayEnd() {
        return formatDate(new Date(), PATTEM_DAY_END);
    }

    /**
     * 获得某天的开始时间?
     *
     * @param dateStr 字符类型的时间?
     * @return 某天的开始时间
     * @author boll
     */
    public static String getDayBegin(String dateStr) {
        if (StringUtils.isEmpty(dateStr) || dateStr.length() < 10) return null;
        return dateStr.substring(0, 10) + " 00:00:00";
    }

    /**
     * 获得某天的开始时�?
     *
     * @param date 时间
     * @return 某天的开始时�?
     * @author boll
     */
    public static String getDayBegin(Date date) {
        if (date == null) return null;
        return formatDate(date, PATTEM_DAY_BEGIN);
    }

    /**
     * @param dateStr 字符类型的时
     * @return 某天的结束时
     * @author boll
     */
    public static String getDayEnd(String dateStr) {
        if (StringUtils.isEmpty(dateStr) || dateStr.length() < 10) return null;
        return dateStr.substring(0, 10) + " 23:59:59";
    }

    public static String getDayEnd(Date date) {
        if (date == null) return null;
        return formatDate(date, PATTEM_DAY_END);
    }

    /**
     * 当前时间是否在一个时间段以内
     *
     * @param begin
     * @param end   结束时间
     * @return 比较结果 -1 在时间段之前，0 在时间段内，1 在时间段end后
     * @author boll
     */
    public static int compareTimeByNow(Date begin, Date end) {
        long now = new Date().getTime();
        if (now < begin.getTime()) return DATE_COMPARE_BEFORE;
        if (now > end.getTime()) return DATE_COMPARE_AFTER;
        return DATE_COMPARE_BETWEEN;
    }

    /**
     * 判断是否在一个时间段内
     *
     * @param begin 开始时间
     * @param end   结束时间
     * @return 比较结果 -1 在时间段之前，0在时间段内，1 在时间段后
     * @author boll
     */
    public static int containTime(String begin, String end, String date) {
        long now = getDate(date).getTime();
        if (now < getDate(begin).getTime()) return DATE_COMPARE_BEFORE;
        if (now > getDate(end).getTime()) return DATE_COMPARE_AFTER;
        return DATE_COMPARE_BETWEEN;
    }

    /**
     * 判断当前时间是否在一段时间内
     *
     * @param begin 开始时间
     * @param end   结束时间
     * @return 比较结果 true 在时间段内  false 不在时间段内
     * @author boll
     */
    public static boolean isBetweenTime(Date begin, Date end) {
        return compareTimeByNow(begin, end) == DATE_COMPARE_BETWEEN;
    }

    /**
     * 判断当前时间是否在一段时间内
     *
     * @param begin 开始时间
     * @param end   结束时间
     * @return 比较结果 true 在时间段内 false 不在时间段内
     * @author boll
     */
    public static boolean isBetweenTime(String begin, String end) {
        return containTime(begin, end, formatDate(new Date())) == DATE_COMPARE_BETWEEN;
    }

    /**
     * 计算当前时间与给出时间的毫秒�?
     *
     * @param date 时间�?
     * @return 毫秒�?
     * @author boll
     */
    public static long calTimeByNow(Date date) {
        return new Date().getTime() - date.getTime();
    }

    /**
     * 计算当前时间与给出时间的毫秒�?
     *
     * @param date 时间�?
     * @return 毫秒�?
     * @author boll
     */
    public static long calTimeByNow(String date) {
        return new Date().getTime() - getDate(date).getTime();
    }

    /**
     * 在当前时间点上加多少天
     *
     * @param days
     * @return
     * @author boll
     */
    public static Date addDays(int days) {
        return new Date(new Date().getTime() + days * ONEDAY_MILLISECONDS);
    }

    public static Date addDays(Date date, int days) {
        return new Date(date.getTime() + days * ONEDAY_MILLISECONDS);
    }

    /**
     * 给指定的时间加上 minute 分钟
     *
     * @param date
     * @param minute
     * @return
     */
    public static Date addMinutes(Date date, int minute) {
        return new Date(date.getTime() + minute * ONEMIN_MILLISECONDS);
    }

    public static String addDays(String date, int days) {
        return addDays(date, days, PATTEM_YYYYMMDD);
    }

    public static String addDays(String date, int days, String pattem) {
        try {
            DateFormat dateFormat = new SimpleDateFormat(pattem);
            Date day = dateFormat.parse(date);
            return dateFormat.format(new Date(day.getTime() + days * ONEDAY_MILLISECONDS));
        } catch (ParseException e) {
            e.printStackTrace();
            return "";
        }
    }

    public static int getWeek() {
        return getWeek(new Date());
    }

    public static int getWeek(String time) {
        Date t = null;
        if (time != null && time.length() >= 10) {
            t = getDate(time.substring(0, 10), PATTEM_DATE);
        } else {
            return -1;
        }
        return getWeek(t);
    }

    public static int getWeek(Date time) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(time);
        return cal.get(Calendar.DAY_OF_WEEK) - 1;
    }

    public static int getDistanceTwoDay(Date arg1, Date arg2) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        try {
            arg1 = sdf.parse(sdf.format(arg1));
            arg2 = sdf.parse(sdf.format(arg2));
        } catch (ParseException e) {
            return -1;
        }
        Calendar cal = Calendar.getInstance();
        cal.setTime(arg1);
        long time1 = cal.getTimeInMillis();
        cal.setTime(arg2);
        long time2 = cal.getTimeInMillis();
        long between_days = Math.abs(time2 - time1) / (1000 * 3600 * 24);
        return (int) between_days;
    }

    public static String addMonth(Date date, int month, String pattem) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.add(Calendar.MONTH, month);
        return formatDate(cal.getTime(), pattem);
    }

    public static Date addMonth(Date date, int month) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.add(Calendar.MONTH, month);
        return cal.getTime();
    }

    /**
     * 日期间隔
     *
     * @param fromDate java.util.Date
     * @param toDate   java.util.Date
     * @return
     */
    public static int dateDiff(Date fromDate, Date toDate) {
        return getDistanceTwoDay(fromDate, toDate);
    }

    /**
     * 是否是日期格式
     * 格式:yyyy-MM-dd 正则会匹配平年和闰年2月份天数
     *
     * @param dateString String
     * @return boolean
     */
    public static boolean isDateFormat(String dateString) {
        return isDateFormat(dateString, YYYY_MM_DD_DATE_FORMAT_REGEXP);
    }

    /**
     * 是否是日期格式
     *
     * @param dateString dateString
     * @param regexp     regexp
     * @return boolean
     */
    public static boolean isDateFormat(String dateString, String regexp) {
        Pattern pattern = Pattern.compile(regexp);
        Matcher matcher = pattern.matcher(dateString);
        return matcher.find();
    }

    /**
     * 获取月初日期
     *
     * @param date Date
     * @return String
     */
    public static String getMonthFirstDay(Date date) {
        Calendar cDay = Calendar.getInstance();
        cDay.setTime(date);
        cDay.set(Calendar.DAY_OF_MONTH, 1);
        return formatDate(cDay.getTime(), PATTEM_DATE);
    }

    /**
     * 获取月末日期
     *
     * @param date Date
     * @return Date
     */
    public static String getMonthLastDay(Date date) {
        Calendar cDay = Calendar.getInstance();
        cDay.setTime(date);
        cDay.set(Calendar.DAY_OF_MONTH, cDay.getActualMaximum(Calendar.DAY_OF_MONTH));
        return formatDate(cDay.getTime(), PATTEM_DATE);
    }
}
